

package cn.shengchao.examstar.product.ohs.remote.rpc;

import cn.shengchao.examstar.knowledge.acl.ports.repositories.IKnowledgePointRepository;
import cn.shengchao.examstar.knowledge.domain.entity.KnowledgePoint;
import cn.shengchao.examstar.product.acl.ports.repositories.INodeKnowledgePointRepository;
import cn.shengchao.examstar.product.domain.entity.CourseConfig;
import cn.shengchao.examstar.product.domain.entity.DiscountConfig;
import cn.shengchao.examstar.product.domain.entity.FreeUnlockConfig;
import cn.shengchao.examstar.product.infrastructure.dao.po.NodeKnowledgePoint;
import cn.shengchao.examstar.product.ohs.local.appservice.CourseService;
import cn.shengchao.examstar.product.ohs.local.appservice.ProductAppService;
import cn.shengchao.examstar.product.ohs.local.message.KnowledgeNodeDto;
import cn.shengchao.examstar.product.ohs.local.message.ProductPayPriceDto;
import cn.shengchao.examstar.rpc.product.api.ICourseNodesRpc;
import cn.shengchao.examstar.rpc.product.req.CourseNodeConfig;
import cn.shengchao.examstar.rpc.product.req.SaveCourseInfo;
import cn.shengchao.examstar.rpc.product.req.SaveCourseNodes;
import cn.shengchao.examstar.rpc.product.res.BatchUnlockConfig;
import cn.shengchao.examstar.rpc.product.res.CourseNodesTree;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.exception.BusinessException;
import top.continew.starter.core.validation.CheckUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;

import static cn.shengchao.base.constant.Constants.RedisKey.PRODUCT_KEY;

@DubboService
public class CourseNodesRpc implements ICourseNodesRpc {

    @Autowired
    private CourseService courseService;

    @Autowired
    private ProductAppService productAppService;

    @Autowired
    private INodeKnowledgePointRepository iNodeKnowledgePointRepository;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private IKnowledgePointRepository iKnowledgePointRepository;

    @Autowired
    private TransactionTemplate transactionTemplate;


    @Transactional
    @Override
    public Long editCourseNodes(SaveCourseNodes saveCourseNodes) {
        //        CheckUtils.throwIf(saveCourseNodes.getParentId().equals(saveCourseNodes.getId()), "章节id不能与章节id重复");
        CheckUtils.throwIfNull(saveCourseNodes.getName(), "章节名称不能为空");
        //知识点必须有价格
//        CheckUtils.throwIf(saveCourseNodes.getIsLesson() == 1 && (saveCourseNodes.getPrice() == null || saveCourseNodes.getPrice().doubleValue() == 0), "知识点价格必须大于0");
//        CheckUtils.throwIf(saveCourseNodes.getIsLesson() == 1 && (saveCourseNodes.getDiscountPrice() == null || saveCourseNodes.getDiscountPrice().doubleValue() == 0), "知识点折扣价格必须大于0");
        if (saveCourseNodes.getIsLesson() == 1) {
            if (saveCourseNodes.getPrice() == null) {
                saveCourseNodes.setPrice(BigDecimal.valueOf(0));
            }
            if (saveCourseNodes.getDiscountPrice() == null) {
                saveCourseNodes.setDiscountPrice(BigDecimal.valueOf(0));
            }
        }
        //保存课程
        Long id = courseService.editCourseNodes(saveCourseNodes);
        RedisUtils.delete(PRODUCT_KEY + id);
        //保存课程知识点关联
        iNodeKnowledgePointRepository.edit(id, saveCourseNodes.getKnowledgePointIds());
//        if (StrUtil.isNotBlank(saveCourseNodes.getPlayUrl())) {
//            CourseUploadEvent courseUploadEvent = new CourseUploadEvent(CourseUploadEvent.CourseUploadMessage.builder()
//                    .videoUrl(saveCourseNodes.getPlayUrl())
//                    .build());
//            applicationEventPublisher.publishEvent(courseUploadEvent);
//        }
        return id;
    }

    @Override
    public SaveCourseNodes getCourseNode(Long nodeId) {
        SaveCourseNodes saveCourseNodes = courseService.getCourseNode(nodeId);
        List<NodeKnowledgePoint> nodeKnowledgePoint = iNodeKnowledgePointRepository.getNodeKnowledgePoint(nodeId);
        saveCourseNodes.setKnowledgePointIds(nodeKnowledgePoint.stream()
                .map(NodeKnowledgePoint::getKnowledgePointId)
                .toList());
        return saveCourseNodes;
    }

    @Override
    public List<CourseNodesTree> getCourseNodesTree(Long courseId) {
        List<KnowledgeNodeDto> knowledgeList = courseService.getKnowledgeList(courseId, "", false);
        CompletableFuture.runAsync(() -> productAppService.updateCoursePrice(knowledgeList.stream().filter(a -> a.getIsLesson() != null && a.getIsLesson() == 1L).toList(), courseId));
        return convertKnowledgeNodesToCourseNodes(knowledgeList);
    }

    @Override
    public void generateChapter(Long courseId, String knowledgePointPath) {
        List<KnowledgePoint> knowledgePoints = iKnowledgePointRepository.getKnowledgePointByPath(knowledgePointPath);
        List<SaveCourseNodes> courseNodesList = CourseNodeBuilder.fromKnowledgePoints(knowledgePoints, courseId, knowledgePointPath);
        transactionTemplate.execute(status -> {
            try {
                CourseNodeTraversal traversal = new CourseNodeTraversal();
                List<CompletableFuture<Void>> completableFutures = new ArrayList<>();
                traversal.traverseCourseNodes(courseNodesList, node -> {
                    completableFutures.add(CompletableFuture.runAsync(() -> {
                        Long id = courseService.editCourseNodes(node);
                        //保存课程知识点关联
                        iNodeKnowledgePointRepository.edit(id, node.getKnowledgePointIds());
                    }));
                });
                CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
                return null;
            } catch (Exception e) {
                status.setRollbackOnly();
                throw new BusinessException("更新失败！");
            }
        });
    }

    @Override
    public void deleteCourseNodes(Long nodeId) {
        RedisUtils.delete(PRODUCT_KEY + nodeId);
        courseService.deleteCourseNodes(nodeId);
    }

    @Transactional
    @Override
    public void editCourseNodeConfig(CourseNodeConfig courseNodeConfig) {
        List<DiscountConfig> discountConfigs = new ArrayList<>();
        CourseConfig courseConfig = new CourseConfig();
        courseConfig.setCourseId(courseNodeConfig.getCourseId());
        courseConfig.setUserId(courseConfig.getUserId());
        for (BatchUnlockConfig batchUnlockConfig : courseNodeConfig.getBatchUnlockConfig()) {
            CheckUtils.throwIf(batchUnlockConfig.getDiscount() <= 0, "折扣不能为空");
            CheckUtils.throwIf(batchUnlockConfig.getCourseNodeSum() <= 1, "数量不能小于1");
            DiscountConfig discountConfig = new DiscountConfig();
            discountConfig.setDiscount(batchUnlockConfig.getDiscount());
            discountConfig.setId(batchUnlockConfig.getId());
            discountConfig.setCourseNodeSum(batchUnlockConfig.getCourseNodeSum());
            discountConfig.setDeleted(batchUnlockConfig.getDeleted());
            discountConfigs.add(discountConfig);
        }
        courseConfig.setDiscountConfig(discountConfigs);
        FreeUnlockConfig freeUnlockConfig = new FreeUnlockConfig();
        freeUnlockConfig.setId(courseNodeConfig.getId());
        freeUnlockConfig.setFreeUnlockSum(courseNodeConfig.getFreeUnlockSum());
        courseConfig.setFreeUnlockConfig(freeUnlockConfig);
        //更新配置
        courseService.editCourseNodeConfig(courseConfig);
        //获取所有知识点
        List<Long> ids = courseService.getKnowledgeIds(courseNodeConfig.getCourseId(), true);
        //计算价格
        ProductPayPriceDto productPayPrice = productAppService.calculateProductPayPrice(String.valueOf(courseNodeConfig
                .getCourseId()), ids);
        SaveCourseInfo saveCourseInfo = new SaveCourseInfo();
        saveCourseInfo.setId(courseNodeConfig.getCourseId());
        saveCourseInfo.setPrice(productPayPrice.getProduct().getPrice());
        saveCourseInfo.setDiscountPrice(productPayPrice.getProduct().getDiscountPrice());
        //更新课程
        courseService.updateCoursePrice(saveCourseInfo);
    }

    @Override
    public CourseNodeConfig getCourseNodeConfig(Long courseId) {
        return courseService.getCourseNodeConfig(courseId);
    }

    public List<CourseNodesTree> convertKnowledgeNodesToCourseNodes(List<KnowledgeNodeDto> knowledgeList) {
        // 1. 创建ID->节点的映射
        Map<Long, CourseNodesTree> nodeMap = new HashMap<>();
        knowledgeList.forEach(dto -> {
            CourseNodesTree node = createNode(dto);
            nodeMap.put(dto.getId(), node);
        });

        // 2. 构建树形结构
        List<CourseNodesTree> rootNodes = new ArrayList<>();
        knowledgeList.forEach(dto -> {
            CourseNodesTree node = nodeMap.get(dto.getId());
            if (dto.getParentId() == null || !nodeMap.containsKey(dto.getParentId())) {
                rootNodes.add(node); // 根节点
            } else {
                CourseNodesTree parent = nodeMap.get(dto.getParentId());
                parent.getChildren().add(node); // 添加子节点
            }
        });

        // 3. 递归计算所有节点的价格（包括子节点价格之和）
        calculateNodePrices(rootNodes);
        rootNodes.sort(Comparator.comparingInt(CourseNodesTree::getSort));
        // 4. 排序（根据sort字段）
        sortTree(rootNodes);
        return rootNodes;
    }

    private void calculateNodePrices(List<CourseNodesTree> nodes) {
        nodes.forEach(node -> {
            if (!node.getChildren().isEmpty()) {
                // 先递归计算所有子节点的价格
                calculateNodePrices(node.getChildren());
                // 计算当前节点的总价格（所有子节点价格之和）
                BigDecimal priceSum = node.getChildren()
                        .stream()
                        .map(CourseNodesTree::getPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                node.setPrice(priceSum);
                BigDecimal discountPriceSum = node.getChildren()
                        .stream()
                        .map(CourseNodesTree::getDiscountPrice)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                node.setDiscountPrice(discountPriceSum);
            }
        });
    }

    private CourseNodesTree createNode(KnowledgeNodeDto dto) {
        CourseNodesTree node = new CourseNodesTree();
        node.setId(dto.getId());
        node.setCourseId(dto.getCourseId());
        node.setIsLesson(dto.getIsLesson());
        node.setParentId(dto.getParentId());
        node.setName(dto.getName());
        node.setPrice(BigDecimal.valueOf(dto.getPrice()));
        node.setDiscountPrice(BigDecimal.valueOf(dto.getDiscountPrice())); // 默认无折扣
        node.setSort(dto.getSort()); // 默认排序值
        node.setChildren(new ArrayList<>());
        return node;
    }

    private void sortTree(List<CourseNodesTree> nodes) {
        nodes.forEach(node -> {
            // 递归排序子节点
            if (!node.getChildren().isEmpty()) {
                node.getChildren().sort(Comparator.comparingInt(CourseNodesTree::getSort));
                sortTree(node.getChildren());
            }
        });
    }
}
